package ru.ifmo.croak.impl.ui.query.team1;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.ifmo.croak.api.Message;
import ru.ifmo.croak.api.MessageQuery;
import ru.ifmo.croak.api.QueryRequest;
import ru.ifmo.croak.api.QueryService;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

class SubscriptionsModel {
    private static final Logger log = LoggerFactory.getLogger(SubscriptionListModel.class);
    private QueryService queryService;


    private class Subscription {
        private QueryRequest queryRequest;
        private MessageQuery messageQuery;

        private Subscription(QueryRequest queryRequest) {
            setQueryRequest(queryRequest);
        }

        public void setQueryRequest(QueryRequest queryRequest) {
            this.queryRequest = queryRequest;
        }

        public void requery(QueryRequest queryRequest) {
            if (messageQuery != null) {
                messageQuery.close();
            }
            this.queryRequest = queryRequest;
            if (queryService != null) {
                messageQuery = queryService.createQuery(queryRequest);
                messageQuery.setMessageListener(messagesModel);
                ArrayList<Message> msgs = new ArrayList<Message>(messageQuery.getMessages());
                log.trace("query.size = {}, size {}", queryRequest.getLimit(), msgs.size());
                Collections.reverse(msgs);
                for (Message msg : msgs) {
                    messagesModel.messageAvailable(msg);
                }
            }
        }


        @Override
        public String toString() {

            return (queryRequest.getAuthor() != null ? queryRequest.getAuthor() : "anybody") + " @ " + (queryRequest.getText() != null ? queryRequest.getText() : "anything");
        }

        public void close() {
            if (messageQuery != null) {
                messageQuery.close();
            }
        }
    }

    class SubscriptionListModel extends AbstractListModel {
        public int getSize() {
            return subscriptions.size();
        }

        public Object getElementAt(int index) {
            return subscriptions.get(index);
        }

        public void fireContentsChanged(int index) {
            super.fireContentsChanged(this, index, index);
        }

        public void fireIntervalAdded(int index) {
            super.fireIntervalAdded(this, index, index);
        }

        public void fireIntervalRemoved(int index) {
            super.fireIntervalRemoved(this, index, index);
        }
    }

    MessagesModel messagesModel;
    Executor executor;

    SubscriptionsModel(QueryService queryService, MessagesModel messagesModel) {
        this.queryService = queryService;
        this.messagesModel = messagesModel;
        subscriptions = new ArrayList<Subscription>();
        listModelAdapter = new SubscriptionListModel();
        executor = Executors.newSingleThreadExecutor();
    }

    ArrayList<Subscription> subscriptions;
    private SubscriptionEditor subscriptionEditor;

    public void setSubscriptionEditor(SubscriptionEditor subscriptionEditor) {
        this.subscriptionEditor = subscriptionEditor;
    }

    SubscriptionListModel listModelAdapter;

    void addSubscription() {
        QueryRequest queryRequest = new QueryRequest();
        queryRequest.setLimit(10);
        subscriptionEditor.startEdit(queryRequest, new SubscriptionEditor.Callback() {
            public void editingComplete(final QueryRequest queryRequest, boolean mustRemove, boolean mustCancel) {
                if (!mustRemove && !mustCancel) {
                    final Subscription subscription = new Subscription(queryRequest);
                    subscriptions.add(subscription);
                    listModelAdapter.fireIntervalAdded(subscriptions.size() - 1);
                    executor.execute(new Runnable() {
                        public void run() {
                            subscription.requery(queryRequest);
                        }
                    });
                }
            }
        });
    }

    void editSubscription(final int index) {
        subscriptionEditor.startEdit(subscriptions.get(index).queryRequest, new SubscriptionEditor.Callback() {
            public void editingComplete(final QueryRequest queryRequest, boolean mustRemove, boolean mustCancel) {
                if (mustRemove) {
                    removeSubscription(index);
                } else if (!mustCancel) {
                    final Subscription subscription = subscriptions.get(index);
                    subscription.setQueryRequest(queryRequest);
                    listModelAdapter.fireContentsChanged(index);
                    executor.execute(new Runnable() {
                        public void run() {
                            subscription.requery(queryRequest);
                        }
                    });
                }

            }
        });
    }

    void removeSubscription(int index) {
        final Subscription subscription = subscriptions.get(index);
        subscriptions.remove(index);
        listModelAdapter.fireIntervalRemoved(index);
        executor.execute(new Runnable() {
            public void run() {
                subscription.close();
            }
        });
    }


    ListModel getListModel() {
        return listModelAdapter;
    }

}
